<template>
  <basic-container>
    <el-tabs v-model="activeName" tab-position="left" type="border-card">
      <el-tab-pane label="连接配置" name="connect">
        <el-card class="mqtt-card">
          <avue-form ref="mqttConnect" v-model="mqttConnect"
                     :option="optionConnect">
            <template #menu-form="{size}">
              <el-button :loading="loading" :disabled="isConnected" type="primary"
                         :size="size"
                         @click="onConnect()">连接
              </el-button>
              <el-button :disabled="!isConnected" plain type="danger" :size="size"
                         @click="disConnect()">断开连接
              </el-button>
              <el-tooltip
                  class="box-item"
                  effect="dark"
                  content="一键导入JSON格式的MQTT连接参数"
                  placement="top-start"
              >
                <el-button :size="size"
                           @click="this.visible=true">配置导入
                </el-button>
              </el-tooltip>
              <el-button :size="size"
                         @click="$refs.mqttConnect.resetForm()">清空
              </el-button>
            </template>
          </avue-form>
          <el-dialog v-model="visible" title="导入 JSON 格式的 MQTT 连接参数" width="800">
            <code-editor
                ref="editor"
                v-model="mqttJson"
                :json="true"
                theme="nord"
                height="200px"
            />
            <template #footer>
              <span class="dialog-footer">
                <el-button @click="visible = false">取 消</el-button>
                <el-button @click="prettyCode">格式化</el-button>
                <el-button type="primary" @click="importSettings">确 定</el-button>
              </span>
            </template>
          </el-dialog>
        </el-card>
      </el-tab-pane>
      <el-tab-pane label="订阅" name="subscribe">
        <el-card class="mqtt-card">
          <el-row>
            <avue-form ref="mqttSubscribe" v-model="mqttSubscribe"
                       :option="optionSubscribe">
              <template #menu-form="{size}">
                <el-tooltip
                    class="box-item"
                    effect="dark"
                    content="mqtt连接成功后方可订阅"
                    placement="top-start"
                >
                  <el-button :disabled="!isConnected" type="primary"
                             :size="size"
                             @click="onSubscribe()">订阅
                  </el-button>
                </el-tooltip>
                <el-button :size="size"
                           @click="$refs.mqttSubscribe.resetForm()">清空
                </el-button>
              </template>
            </avue-form>
          </el-row>
          <el-row>
            <el-col>
              <el-card class="mqtt-card" shadow="hover">
                <template #header>
                  <div class="card-header">
                    <span>列表</span>
                  </div>
                </template>
                <mqtt-table v-model="this.dataSubscribe" @onRemove="unSubscribe"></mqtt-table>
              </el-card>
            </el-col>
          </el-row>
        </el-card>
      </el-tab-pane>
      <el-tab-pane label="发布" name="publish">
        <el-card class="mqtt-card">
          <el-row>
            <avue-form ref="mqttPublish" v-model="mqttPublish"
                       :option="optionPublish">
              <template #menu-form="{size}">
                <el-tooltip
                    class="box-item"
                    effect="dark"
                    content="mqtt连接成功后方可订阅"
                    placement="top-start"
                >
                  <el-button :disabled="!isConnected" type="primary"
                             :size="size"
                             @click="onPublish()">发布
                  </el-button>
                </el-tooltip>
                <el-button :size="size"
                           @click="$refs.mqttPublish.resetForm()">清空
                </el-button>
              </template>
            </avue-form>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-card class="mqtt-card" shadow="hover">
                <template #header>
                  <div class="card-header">
                    <span>已接收</span>
                  </div>
                </template>
                <mqtt-table v-model="dataReceive" :payload="true" :view-mode="true"></mqtt-table>
              </el-card>
            </el-col>
            <el-col :span="12">
              <el-card class="mqtt-card" shadow="hover">
                <template #header>
                  <div class="card-header">
                    <span>已发送</span>
                  </div>
                </template>
                <mqtt-table v-model="dataSend" :payload="true" :view-mode="true"></mqtt-table>
              </el-card>
            </el-col>
          </el-row>
        </el-card>
      </el-tab-pane>
    </el-tabs>
  </basic-container>
</template>
<script>
import {deepClone} from "@/utils/util";
import mqtt from 'mqtt';
import {validatejson} from "@/utils/validate";

export default {
  data() {
    return {
      client: null,
      mode: 'disconnect',
      activeName: 'connect',
      isConnected: false,
      visible: false,
      loading: false,
      reconnectCount: 0,
      mqttJson: '',
      mqttConnect: {},
      mqttSubscribe: {},
      mqttPublish: {},
      optionConnect: {
        submitBtn: false,
        emptyBtn: false,
        column: [
          {
            label: "host",
            prop: "host",
            value: ""
          },
          {
            label: "port",
            prop: "webPort",
            value: ""
          },
          {
            label: "clientId",
            prop: "clientId",
            value: "",
          },
          {
            label: "keepalive",
            prop: "keepalive",
            value: 60,
          },
          {
            label: "username",
            prop: "username",
          },
          {
            label: "password",
            prop: "password",
          },
          /*{
            label: "version",
            prop: "mqttVersion",
            type: "select",
            dicData: [
              {
                label: "MQTT 3.1.1",
                value: "3.1.1"
              },
              {
                label: "MQTT 5",
                value: "5"
              },
            ],
            value: "5"
          },*/
        ]
      },
      optionSubscribe: {
        submitBtn: false,
        emptyBtn: false,
        column: [
          {
            label: "Topic",
            prop: "topic",
            rules: [{
              required: true,
              message: "请输入topic",
              trigger: "blur"
            }]
          },
          {
            label: "QoS",
            prop: "qos",
            type: "select",
            dicData: [
              {
                label: "0 - 最多一次",
                value: 0
              },
              {
                label: "1 - 最少一次",
                value: 1
              },
              {
                label: "2 - 仅一次",
                value: 2
              },
            ],
            value: 0,
            rules: [{
              required: true,
              message: "请选择QoS",
              trigger: "blur"
            }]
          },
        ]
      },
      optionPublish: {
        submitBtn: false,
        emptyBtn: false,
        column: [
          {
            label: "Topic",
            prop: "topic",
            rules: [{
              required: true,
              message: "请输入topic",
              trigger: "blur"
            }]
          },
          {
            label: "QoS",
            prop: "qos",
            type: "select",
            dicData: [
              {
                label: "0 - 最多一次",
                value: 0
              },
              {
                label: "1 - 最少一次",
                value: 1
              },
              {
                label: "2 - 仅一次",
                value: 2
              },
            ],
            value: 0,
            rules: [{
              required: true,
              message: "请选择QoS",
              trigger: "blur"
            }]
          },
          {
            label: "Payload",
            prop: "payload",
            type: "textarea",
            span: 24,
            rules: [{
              required: true,
              message: "请输入payload",
              trigger: "blur"
            }]
          },
        ]
      },
      dataSubscribe: [],
      dataReceive: [],
      dataSend: [],
    }
  },
  created() {
    this.init();
  },
  methods: {
    init() {

    },
    importSettings() {
      if (!validatejson(this.mqttJson)) {
        this.$message.error('参数格式不正确');
        return;
      }
      this.mqttConnect = {
        ...this.mqttConnect,
        ...JSON.parse(this.mqttJson)
      };
      this.visible = false;
    },
    prettyCode() {
      this.$refs.editor.prettyCode();
    },
    onConnect() {
      this.loading = true;

      const url = `ws://${this.mqttConnect.host}:${this.mqttConnect.webPort}/`;
      const clientId = this.mqttConnect.clientId;
      const username = this.mqttConnect.username;
      const password = this.mqttConnect.password;
      const keepalive = this.mqttConnect.keepalive;

      // 创建客户端
      this.client = mqtt.connect(url, {
        clientId,
        username,
        password,
        keepalive
      });

      // 连接成功
      this.client.on('connect', () => {
        this.isConnected = true;
        this.loading = false;
        this.onMessage();
        this.$message.success('连接成功');

      });

      // 无限重连限制次数
      this.client.on('reconnect', () => {
        this.reconnectCount = this.reconnectCount + 1;
        if (this.reconnectCount > 2) {
          this.isConnected = false;
          this.loading = false;
          this.client.end(); // 关闭连接
        }
      });

      // 监听连接错误事件
      this.client.on('error', (error) => {
        this.isConnected = false;
        this.loading = false;
        this.client.end(); // 关闭连接
        this.$message.error('连接失败：' + error);
      });

    },
    disConnect() {
      if (this.isConnected) {
        // 关闭连接
        this.client.end(true, () => {
          this.isConnected = false;
          this.$message.success('连接关闭');
        });
      }
    },
    onSubscribe() {
      this.$refs.mqttSubscribe.validate((valid, done) => {
        if (valid) {
          const _this = this;
          const data = deepClone(this.mqttSubscribe);
          if (this.dataSubscribe.find(item => item.topic === data.topic)) {
            this.$message.warning('已订阅该主题');
            done()
            return false;
          }

          data.id = new Date().getTime();
          data.time = new Date().toLocaleString();
          this.client.subscribe(data.topic, {qos: data.qos}, function (err) {
            if (!err) {
              _this.dataSubscribe.unshift(data);
              _this.$message.success(`topic: [${data.topic}] 订阅成功`);
            } else {
              _this.$message.error(`topic: [${data.topic}] 订阅失败:` + err);
            }
          });
          done()
        } else {
          return false;
        }
      })
    },
    unSubscribe(row) {
      this.client.unsubscribe(row.topic, (err) => {
        if (!err) {
          this.$message.success(`topic: [${row.topic}] 取消订阅成功`);
        } else {
          this.$message.error(`topic: [${row.topic}] 取消订阅失败:` + err);
        }
      });
    },
    onPublish() {
      const data = deepClone(this.mqttPublish);
      if (!validatejson(data.payload)) {
        this.$message.error('payload参数JSON格式不正确');
        return;
      }
      data.id = new Date().getTime();
      data.time = new Date().toLocaleString();
      this.client.publish(data.topic, JSON.stringify(JSON.parse(data.payload)), {qos: data.qos}, (err) => {
        if (!err) {
          this.dataSend.unshift(data);
          this.$message.success(`topic: [${data.topic}] 发布成功, payload: [${data.payload}]`);
        } else {
          this.$message.error(`topic: [${data.topic}] 发布失败:` + err);
        }
      });
    },
    onMessage() {
      this.client.on('message', (topic, message) => {
        const data = {
          id: new Date().getTime(),
          topic,
          payload: message.toString(),
          time: new Date().toLocaleString()
        };
        this.dataReceive.unshift(data);
      });
    }
  }
}
</script>
<style scoped>
.mqtt-card {
  margin-bottom: 20px;
}
</style>
